/*!
 *  Copyright (C) 2011  Anthony Wertz.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <cppunit/extensions/HelperMacros.h>
#include "StatGenTest.h"

#include "StatGen.h"
#include <string.h>

CPPUNIT_TEST_SUITE_REGISTRATION( StatGenTest );

//------------------------------------------------------------------------------

void StatGenTest::testInvalidList( void )
{
  // Send a pointer to an invalid list.
  GradeType * grades = reinterpret_cast<GradeType *>( 0 );    // Invalid pointer.
  unsigned int numberOfGrades           = 25;                 // Invalid element count.
  unsigned int studentsAtOrBelowAverage = 12;
  unsigned int studentsAboveAverage     = 24;
  
  // The function call should not pass.
  CPPUNIT_ASSERT_EQUAL(
    false,
    StatGen( grades, numberOfGrades, studentsAtOrBelowAverage, studentsAboveAverage ) );
    
  // Because an invalid list was passed, the output parameters should not have
  // been modified.
  CPPUNIT_ASSERT_EQUAL( 12u, studentsAtOrBelowAverage );
  CPPUNIT_ASSERT_EQUAL( 24u, studentsAboveAverage );
}

//------------------------------------------------------------------------------

void StatGenTest::testZeroElements( void )
{
  // Send a list with no (valid) elements.
  GradeType grades[ 1 ];                                      // Valid data, uninitialized elements.
  unsigned int numberOfGrades           =  0;                 // Don't analyze any grades.
  unsigned int studentsAtOrBelowAverage = 12;
  unsigned int studentsAboveAverage     = 24;
  
  // The function call should pass.
  CPPUNIT_ASSERT_EQUAL(
    true,
    StatGen( grades, numberOfGrades, studentsAtOrBelowAverage, studentsAboveAverage ) );
    
  // No students analyzed.
  CPPUNIT_ASSERT_EQUAL( 0u, studentsAtOrBelowAverage );
  CPPUNIT_ASSERT_EQUAL( 0u, studentsAboveAverage );
}

//------------------------------------------------------------------------------

void StatGenTest::testOneElement( void )
{
  // Send a list with a single element.
  const unsigned int numberOfGrades     =  1;
  GradeType grades[ numberOfGrades ]    =
  {
    GradeType( 10023, 72.3 )
  };
  unsigned int studentsAtOrBelowAverage = 12;
  unsigned int studentsAboveAverage     = 24;
  
  // The function call should pass.
  CPPUNIT_ASSERT_EQUAL(
    true,
    StatGen( grades, numberOfGrades, studentsAtOrBelowAverage, studentsAboveAverage ) );
    
  // Only one student, meaning that grade is the sample mean, and (s)he is "at"
  // or below it.
  CPPUNIT_ASSERT_EQUAL( 1u, studentsAtOrBelowAverage );
  CPPUNIT_ASSERT_EQUAL( 0u, studentsAboveAverage );
}

//------------------------------------------------------------------------------

void StatGenTest::testMultipleElements( void )
{
  // Test two elements (boundary case).
  {
    // Send a pointer to an invalid list.
    const unsigned int numberOfGrades     =  2;
    GradeType grades[ numberOfGrades ]    =
    {
      GradeType( 10023, 72.3 ),
      GradeType( 10025, 98.6 )
    };
    unsigned int studentsAtOrBelowAverage = 12;
    unsigned int studentsAboveAverage     = 24;
    
    // The function call should pass.
    CPPUNIT_ASSERT_EQUAL(
      true,
      StatGen( grades, numberOfGrades, studentsAtOrBelowAverage, studentsAboveAverage ) );
      
    // Average is (72.3 + 98.6)/2 = 85.45. One above, one below.
    CPPUNIT_ASSERT_EQUAL( 1u, studentsAtOrBelowAverage );
    CPPUNIT_ASSERT_EQUAL( 1u, studentsAboveAverage );
  }

  // Test two elements (boundary case).
  {
    // Send a pointer to an invalid list.
    const unsigned int numberOfGrades     =  2;
    GradeType grades[ numberOfGrades ]    =
    {
      GradeType( 10023, 86.3 ),
      GradeType( 10025, 86.3 )
    };
    unsigned int studentsAtOrBelowAverage = 12;
    unsigned int studentsAboveAverage     = 24;
    
    // The function call should pass.
    CPPUNIT_ASSERT_EQUAL(
      true,
      StatGen( grades, numberOfGrades, studentsAtOrBelowAverage, studentsAboveAverage ) );
      
    // Average is 2*(86.3)/2 = 86.3. Both at or below.
    CPPUNIT_ASSERT_EQUAL( 2u, studentsAtOrBelowAverage );
    CPPUNIT_ASSERT_EQUAL( 0u, studentsAboveAverage );
  }

  // Small class.
  {
    // Send a pointer to an invalid list.
    const unsigned int numberOfGrades     =  15;
    GradeType grades[ numberOfGrades ]    =
    {
      GradeType( 10091, 86.3 ),
      GradeType( 10302, 74.7 ),
      GradeType( 10001, 96.8 ),
      GradeType( 12302, 83.2 ),
      GradeType( 10001, 37.3 ),
      GradeType( 10502, 56.7 ),
      GradeType( 10001, 98.8 ),
      GradeType( 10462, 89.2 ),
      GradeType( 10071, 70.1 ),
      GradeType( 10242, 71.5 ),
      GradeType( 17322, 65.2 ),
      GradeType( 10031, 73.1 ),
      GradeType( 10631, 98.1 ),
      GradeType( 10342, 93.5 ),
      GradeType( 10662, 15.2 )
    };
    unsigned int studentsAtOrBelowAverage = 12;
    unsigned int studentsAboveAverage     = 24;
    
    // The function call should pass.
    CPPUNIT_ASSERT_EQUAL(
      true,
      StatGen( grades, numberOfGrades, studentsAtOrBelowAverage, studentsAboveAverage ) );
      
    // Average is ... all those numbers added up divided by 15 = 73.98
    CPPUNIT_ASSERT_EQUAL( 7u, studentsAtOrBelowAverage );
    CPPUNIT_ASSERT_EQUAL( 8u, studentsAboveAverage );
  }
}

//------------------------------------------------------------------------------

